/******************************************************************************************************
	@Name EDP Protocol Stack
	@Author ZZY~
	@Version Universal
	@Time 2018/1/10 22:15
	@Information Onenet平台的EDP协议栈通用版,可以生成登录,上传,命令回复,心跳的数据包,可以注册命令,可以自动解析
	@Platform 目前已经经过测试证明可移植的硬件平台有:	STM32F103系列
																										STC15F系列
																										STC12C5A60S2
																										Tensilica L106 ESP8266芯片处理器
******************************************************************************************************/
#include "EDP.h"
#include "stm32f10x.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "EDP_CMD.h"
#include "FreeRTOS.h"
#ifndef CONNECT_TIME
	#define CONNECT_TIME 300
#endif
//__ASM uint32_t __REV16(uint16_t value)
//{
//  rev16 r0, r0
//  bx lr
//}
/***********************************************************************************************************************
以下为EDP命令表
***********************************************************************************************************************/
const CMD_Node CMD_Table[] = //命令回调注册表
{
	0
};
/***********************************************************************************************************************
以下为EDP协议有关函数
***********************************************************************************************************************/
uint32_t EDP_login(uint8_t **Pack)//返回登录包长度,同时数据写入Pack指针
{
	uint8_t *Tool;
	uint32_t Pack_Lenth = sizeof(EDP_Login_t);//总长度
#if (LOGIN == WAY_1)
	if(Pack == NULL) return 0;//如果输入为空
	if(*Pack == NULL)//如果用户的指针还没有内存
	{
		*Pack =(uint8_t*)EDP_malloc(sizeof(EDP_Login_t));//为数据包分配内存
		if(*Pack == NULL) return NULL;
	}
	Tool = *Pack;
	((pEDP(Login))Tool)->Message_Type = Login_request;//第一字节消息类型,登录请求
	((pEDP(Login))Tool)->Remain_Lenth = sizeof(EDP_Login_t)-2;//第二字节剩余长度
	((pEDP(Login))Tool)->Protocol_Lenth = Data_convert_16(3);//协议名称长度,固定为3
	((pEDP(Login))Tool)->Protocol[0] = 'E';//协议名称
	((pEDP(Login))Tool)->Protocol[1] = 'D';
	((pEDP(Login))Tool)->Protocol[2] = 'P';
	((pEDP(Login))Tool)->Protocol_Version = 1;//协议版本
	((pEDP(Login))Tool)->Connect_Flag = 0x40;//连接标志,第一种方式
	((pEDP(Login))Tool)->Connect_Time = Data_convert_16(CONNECT_TIME);//保持连接时间
	((pEDP(Login))Tool)->Device_ID_Lenth = Data_convert_16(DEVICE_ID_LENTH);//设备ID长度,小端
	memcpy(((pEDP(Login))Tool)->Device_ID,DeviceID,DEVICE_ID_LENTH);//设备ID
	((pEDP(Login))Tool)->ApiKey_Lenth = Data_convert_16(APIKEY_LENTH);//APIKEY长度,小端
	memcpy(((pEDP(Login))Tool)->ApiKey,APIKEY,APIKEY_LENTH);//APIKEY
#endif
#if (LOGIN == WAY_2)
	uint32_t digit,x = sizeof(EDP(Login))-2;
	if(Pack == NULL) return 0;//如果输入为空
	if(*Pack == NULL)//如果用户的指针还没有内存
	{
		*Pack =(uint8_t*)EDP_malloc(sizeof(EDP(Login)));//为数据包分配内存
		if(*Pack == NULL) return NULL;
	}
	Tool = *Pack;
	((pEDP(Login))Tool)->Message_Type = Login_request;//第一字节消息类型,登录请求
	((pEDP(Login))Tool)->Protocol_Lenth = Data_convert_16(3);//协议名称长度,固定为3
	((pEDP(Login))Tool)->Protocol[0] = 'E';//协议名称
	((pEDP(Login))Tool)->Protocol[1] = 'D';
	((pEDP(Login))Tool)->Protocol[2] = 'P';
	((pEDP(Login))Tool)->Protocol_Version = 1;//协议版本
	((pEDP(Login))Tool)->Connect_Flag = 0xC0;//连接标志,第二种方式
	((pEDP(Login))Tool)->Connect_Time = Data_convert_16(CONNECT_TIME);//保持连接时间
	((pEDP(Login))Tool)->Device_ID_Lenth = 0;//方式2情况下没有设备ID,但是也必须填写长度,所以此值为0
	((pEDP(Login))Tool)->Product_ID_Lenth = Data_convert_16(PRODUCT_ID_LENTH);//产品ID长度
	memcpy(((pEDP(Login))Tool)->Product_ID,ProductID,PRODUCT_ID_LENTH);//产品ID
	((pEDP(Login))Tool)->AuthInfo_Lenth = Data_convert_16(AUTHINFO_LENTH);//鉴权信息长度
	memcpy(((pEDP(Login))Tool)->AuthInfo,AuthInformation,AUTHINFO_LENTH);//鉴权信息
	do{digit = x%128;x /= 128;if(x) digit |= 0x80;*++Tool = digit;}while(x);//编码不定长字节,采用EDP文档给出的算法
#endif
	return Pack_Lenth;
}
uint8_t EDP_Get_Login_Info(uint8_t *Pack)
{
	return ((pEDP(Login_Respond))Pack)->Respond_Code;//返回码
}
uint32_t EDP_PushData(uint8_t **Pack,char* Dest,uint32_t Data_Lenth)
{
	uint16_t digit,x;//用于编码不定长字节
	uint8_t *Tool;//工具指针
	uint32_t Pack_Lenth = 3+strlen(Dest);//总长度
	
	x = Pack_Lenth+Data_Lenth-1;
	if(Pack == NULL) return 0;
	if(*Pack == NULL)
	{
		*Pack = (uint8_t*)EDP_malloc(Pack_Lenth+4);//为数据包分配内存
		if(*Pack == NULL) return NULL;//分配失败
	}
	Tool = *Pack;
	*Tool++ = Push_data_request;//推送数据请求
	do{digit = x%128;x /= 128;if(x) digit |= 0x80;*Tool++ = digit;Pack_Lenth++;}while(x);//编码不定长字节,采用EDP文档给出的算法
	x = strlen(Dest);//计算目标长度
	*(uint16_t*)Tool = Data_convert_16(x); Tool+=2;//临时扩增为16位写入
	memcpy(Tool,Dest,x);//添加目标
	return Pack_Lenth;
}
uint8_t EDP_Get_Close_Info(uint8_t *Pack)
{
	return ((pEDP(Connect_Close))Pack)->Error_Code;//返回错误码
}
uint32_t EDP_SaveData(uint8_t **Pack,char* Dest,uint16_t Number,SaveData_Type_t SaveData_Type,uint32_t Data_Lenth)
{
	uint16_t digit,x;
	uint8_t *Tool,Flag = 0;
	uint32_t Pack_Lenth = 5;//有五个字节是固定的
	
	if(Pack == NULL) return 0;//如果输入为空
	if(Dest != NULL) {Pack_Lenth += (2+strlen(Dest));Flag |= 0x80;}//是否需要转发
	if(Number != NULL) {Pack_Lenth += 2;Flag |= 0x40;}//是否有消息编号
	if(SaveData_Type == Float_With_Time) Pack_Lenth -= 2;//类型五数据长度,少两个字节
	
	
	if(*Pack == NULL)//如果用户的指针还没有内存
	{
		*Pack = (uint8_t*)EDP_malloc(Pack_Lenth+4);//为真正的数据包分配内存
		if(*Pack == NULL) return NULL;
	}
	Tool = *Pack;
	
	x = Pack_Lenth-1+Data_Lenth;//计算剩余长度
	
	*Tool++ = Save_data_request;//储存并转发请求
	do{digit = x%128;x /= 128;if(x) digit |= 0x80;*Tool++ = digit;Pack_Lenth+=1;}while(x);//编码不定长字节,采用EDP文档给出的算法
	*Tool++ = Flag;//标志
	if(Dest != NULL) {x = strlen(Dest); *((uint16_t*)Tool) = Data_convert_16(x);Tool+=2;memcpy(Tool,Dest,x);Tool+=x;}//如果有转发目标,则填入
	if(Number != NULL) {*((uint16_t*)Tool) = Data_convert_16(Number); Tool+=2;}//如果有消息编号,则写入
	
	if(SaveData_Type == Float_With_Time) *Tool = SaveData_Type;//Float_With_Time数据类型
	else *Tool++ = SaveData_Type;*(uint16_t*)Tool = Data_convert_16(Data_Lenth);//其他的数据类型
	
	return Pack_Lenth;
}
uint8_t EDP_Get_SaveData_Info(uint8_t* Pack)
{
	return ((pEDP(SaveData_Respond))Pack)->Code;//返回码
}
uint8_t EDP_CMD_Handle(uint8_t *Pack)
{
	short CMD_Counter = (sizeof(CMD_Table)/sizeof(CMD_Node))-1;//最后一个命令的下标,查找命令是从后往前找
	cb_in input;//提取输入值用的变量
	for(;CMD_Counter>=0;CMD_Counter--)
	{
		if(sscanf(((pEDP(Command))Pack)->CMD,CMD_Table[CMD_Counter]._CMD,&input))//扫描命令并且读入命令值
		{
			CMD_Table[CMD_Counter].Callback(input);//调用回调函数
			return 1;//退出
		}
	}
	#if CMD_NOT_REGISIT_HANDLE
		Unknow_CMD_Handle(((pEDP(Command))Pack)->CMD);//当没有找到命令时的处理,由使用者指定调用哪个函数
	#endif
	return 0;
}
uint32_t EDP_CMD_Respond(uint8_t **Pack,char *Data,char *Res)
{
	uint8_t *Tool,Res_Len;
	uint32_t Pack_Lenth;
	if(Pack == NULL) return 0;//如果输入为空
	if(((pEDP(Command))Data)->Message_Type == Command_request)//如果输入的是完整的数据包
	{
		if(Res)//如果指定了回复内容
		{
			Res_Len = strlen(Res);//返回的内容长度
			Pack_Lenth = sizeof(EDP(Command))+Res_Len-1;//计算所需内存大小
			if(*Pack == NULL)//如果用户的指针还没有内存
			{
				*Pack = (uint8_t*)EDP_malloc(Pack_Lenth);//为数据包分配内存
				if(*Pack == NULL) return 0;
			}
			Tool = *Pack;
			
			memcpy(Tool,Data,sizeof(EDP(Command)));//添加除回复以外的内容,包括UUID
			((pEDP(Command))Tool)->Message_Type = Command_response;//修改第一字节
			((pEDP(Command))Tool)->Remain_Lenth = Pack_Lenth-2;//修改剩余长度
			((pEDP(Command))Tool)->CMD_lenth = Data_convert_32(Res_Len);//修改返回内容长度
			memcpy(((pEDP(Command))Tool)->CMD,Res,Res_Len);//添加回复
		}
		else//如果没有指定,则将包中的命令作为回复
		{
			Res_Len = Data_convert_32(((pEDP(Command))Data)->CMD_lenth);//返回的内容长度
			Pack_Lenth = sizeof(EDP(Command))+Res_Len-1;//计算所需内存大小
			if(*Pack == NULL)//如果用户的指针还没有内存
			{
				*Pack = (uint8_t*)EDP_malloc(Pack_Lenth);//为数据包分配内存
				if(*Pack == NULL) return 0;
			}
			Tool = *Pack;
			
			memcpy(Tool,Data,Pack_Lenth);//添加整个包,回复内容为命令本体
			((pEDP(Command))Tool)->Message_Type = Command_response;//修改第一字节
		}
	}
	else//如果仅输入了UUID
	{
		if(Res)//如果指定了回复内容
		{
			Res_Len = strlen(Res);//返回的内容长度
			Pack_Lenth = sizeof(EDP(Command))+Res_Len-1;//计算所需内存大小
			if(*Pack == NULL)//如果用户的指针还没有内存
			{
				*Pack = (uint8_t*)EDP_malloc(Pack_Lenth);//为数据包分配内存
				if(*Pack == NULL) return 0;
			}
			Tool = *Pack;
			
			((pEDP(Command))Tool)->Message_Type = Command_response;//写入第一字节
			((pEDP(Command))Tool)->Remain_Lenth = (Pack_Lenth-2);//写入剩余长度
			((pEDP(Command))Tool)->CMD_ID_lenth = Data_convert_16(CMD_ID_LENTH);//添加命令ID长度
			memcpy(((pEDP(Command))Tool)->CMD_ID,Data,CMD_ID_LENTH);//添加命令ID
			((pEDP(Command))Tool)->CMD_lenth = Data_convert_32(Res_Len);//添加回复内容长度
			memcpy(((pEDP(Command))Tool)->CMD,Res,Res_Len);//添加回复
		}
		else//如果没有指定,则将字符串Success作为回复
		{
			Pack_Lenth = sizeof(EDP(Command))+6;//计算所需内存大小
			if(*Pack == NULL)//如果用户的指针还没有内存
			{
				*Pack = (uint8_t*)EDP_malloc(Pack_Lenth);//为数据包分配内存
				if(*Pack == NULL) return NULL;
			}
			Tool = *Pack;
			
			((pEDP(Command))Tool)->Message_Type = Command_response;//写入第一字节
			((pEDP(Command))Tool)->Remain_Lenth = (Pack_Lenth-2);//写入剩余长度
			((pEDP(Command))Tool)->CMD_ID_lenth = Data_convert_16(CMD_ID_LENTH);//添加命令ID长度
			memcpy(((pEDP(Command))Tool)->CMD_ID,Data,CMD_ID_LENTH);//添加命令ID
			((pEDP(Command))Tool)->CMD_lenth = Data_convert_32(7);//添加回复内容长度
			memcpy(((pEDP(Command))Tool)->CMD,"Success",7);//添加回复
		}
	}
	return Pack_Lenth;
}
